<?php
require_once 'lib/phpunit/TestCase.php';
require_once "lib/bigfoot/bigfoot.php";

class BigfootStoreTest extends PHPUnit_TestCase {


  function test_get_metabox() {
    $store = new BigfootStore("http://example.org/store");
    $this->assertEquals( "http://example.org/store/meta", $store->get_metabox()->uri );
  }

  function test_get_sparql_service() {
    $store = new BigfootStore("http://example.org/store");
    $this->assertEquals( "http://example.org/store/services/sparql", $store->get_sparql_service()->uri );
  }


}

/*****************************************************************************
*****************************************************************************/
class BigfootMetaboxTest extends PHPUnit_TestCase {
  var $_empty_changeset = '<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:cs="http://purl.org/vocab/changeset/schema#">
  <rdf:Description rdf:nodeID="cs">
    <rdf:type rdf:resource="http://purl.org/vocab/changeset/schema#ChangeSet" />
    <cs:subjectOfChange rdf:nodeID="a" />
    <cs:creatorName>Ian</cs:creatorName>
    <cs:changeReason>PHP Client Test</cs:changeReason>
  </rdf:Description>
</rdf:RDF>';


  function test_apply_changeset_rdfxml_posts_to_metabox_uri() {
    $fake_request_factory = new FakeRequestFactory();
    $fake_request = new FakeHttpRequest( new HttpResponse() );
    $fake_request_factory->register('POST', "http://example.org/store/meta", $fake_request );

    $mb = new BigfootMetabox("http://example.org/store/meta");
    $mb->request_factory = $fake_request_factory;

    $response = $mb->apply_changeset_rdfxml( $this->_empty_changeset );
    $this->assertTrue( $fake_request->was_executed() );
  }

  function test_apply_changeset_rdfxml_posts_supplied_rdfxml() {
    $fake_request_factory = new FakeRequestFactory();
    $fake_request = new FakeHttpRequest( new HttpResponse() );
    $fake_request_factory->register('POST', "http://example.org/store/meta", $fake_request );

    $mb = new BigfootMetabox("http://example.org/store/meta");
    $mb->request_factory = $fake_request_factory;

    $response = $mb->apply_changeset_rdfxml( $this->_empty_changeset );
    $this->assertEquals( $this->_empty_changeset , $fake_request->get_body() );
  }

  function test_apply_changeset_rdfxml_sets_content_type() {
    $fake_request_factory = new FakeRequestFactory();
    $fake_request = new FakeHttpRequest( new HttpResponse() );
    $fake_request_factory->register('POST', "http://example.org/store/meta", $fake_request );

    $mb = new BigfootMetabox("http://example.org/store/meta");
    $mb->request_factory = $fake_request_factory;

    $response = $mb->apply_changeset_rdfxml( $this->_empty_changeset );
    $this->assertTrue( in_array('Content-Type: application/rdf+xml; charset=utf-8', $fake_request->get_headers() ) );
  }

  function test_apply_changeset_rdfxml_sets_accept() {
    $fake_request_factory = new FakeRequestFactory();
    $fake_request = new FakeHttpRequest( new HttpResponse() );
    $fake_request_factory->register('POST', "http://example.org/store/meta", $fake_request );

    $mb = new BigfootMetabox("http://example.org/store/meta");
    $mb->request_factory = $fake_request_factory;

    $response = $mb->apply_changeset_rdfxml( $this->_empty_changeset );
    $this->assertTrue( in_array('Accept: */*', $fake_request->get_headers() ) );
  }
}

/*****************************************************************************
*****************************************************************************/
class HttpRequestTest extends PHPUnit_TestCase {

  function test_set_accept() {
    $req = new HttpRequest("GET", "http://example.org/");
    $req->set_accept("text/plain");

    $this->assertTrue( in_array('Accept: text/plain', $req->get_headers() ) );
  }

  function test_set_accept_overwrites_existing_value() {
    $req = new HttpRequest("GET", "http://example.org/");
    $req->set_accept("text/plain");
    $req->set_accept("application/xml");

    $this->assertFalse( in_array('Accept: text/plain', $req->get_headers() ) );
  }


  function test_set_content_type() {
    $req = new HttpRequest("GET", "http://example.org/");
    $req->set_content_type("text/plain");

    $this->assertTrue( in_array('Content-Type: text/plain', $req->get_headers() ) );
  }

  function test_set_content_type_overwrites_existing_value() {
    $req = new HttpRequest("GET", "http://example.org/");
    $req->set_content_type("text/plain");
    $req->set_content_type("application/xml");

    $this->assertFalse( in_array('Content-Type: text/plain', $req->get_headers() ) );
  }

  function test_set_body_sets_content_length() {
    $req = new HttpRequest("GET", "http://example.org/");
    $req->set_body("now is the time");

    $this->assertTrue( in_array('Content-Length: 15', $req->get_headers() ) );
  }
}

/*****************************************************************************
*****************************************************************************/
class FakeHttpRequest extends HttpRequest {
  var $was_executed  = false;
  var $response;

  function FakeHttpRequest( $response ) {
    $this->was_executed = false;
    $this->response = $response;
  } 

  function execute() {
    $this->was_executed = true;
    return $this->response;
  }

  function was_executed() {
    return $this->was_executed;
  }
}
/*****************************************************************************
*****************************************************************************/
class FakeRequestFactory extends HttpRequestFactory {
  var $requests;

  function FakeRequestFactory() {
    $this->requests = array();
  }

  function register($method, $uri, $request ) {
    $this->requests[$method . ' ' . $uri] = $request;
  }

  function make( $method, $uri ) {
    if (array_key_exists( $method . ' ' . $uri, $this->requests) ) {
      return $this->requests[$method . ' ' . $uri];
    }


    
    return new FakeHttpRequest( new HttpResponse() );
  }

}

/*****************************************************************************
*****************************************************************************/
class BigfootSparqlServiceTest extends PHPUnit_TestCase {

  function test_describe_single_uri_posts_to_service_uri() {
    $fake_request_factory = new FakeRequestFactory();
    $fake_request = new FakeHttpRequest( new HttpResponse() );
    $fake_request_factory->register('POST', "http://example.org/store/services/sparql", $fake_request );

    $ss = new BigfootSparqlService("http://example.org/store/services/sparql");
    $ss->request_factory = $fake_request_factory;

    $response = $ss->describe( 'http://example.org/scooby' );
    $this->assertTrue( $fake_request->was_executed() );
  }

  function test_describe_single_uri_posts_query() {
    $fake_request_factory = new FakeRequestFactory();
    $fake_request = new FakeHttpRequest( new HttpResponse() );
    $fake_request_factory->register('POST', "http://example.org/store/services/sparql", $fake_request );

    $ss = new BigfootSparqlService("http://example.org/store/services/sparql");
    $ss->request_factory = $fake_request_factory;

    $response = $ss->describe( 'http://example.org/scooby' );
    $this->assertEquals( "query=DESCRIBE+%3Chttp%3A%2F%2Fexample.org%2Fscooby%3E", $fake_request->get_body() );
  }

  function test_apply_changeset_rdfxml_sets_accept() {
    $fake_request_factory = new FakeRequestFactory();
    $fake_request = new FakeHttpRequest( new HttpResponse() );
    $fake_request_factory->register('POST', "http://example.org/store/services/sparql", $fake_request );

    $ss = new BigfootSparqlService("http://example.org/store/services/sparql");
    $ss->request_factory = $fake_request_factory;

    $response = $ss->describe( 'http://example.org/scooby' );
    $this->assertTrue( in_array('Accept: application/rdf+xml', $fake_request->get_headers() ) );
  }

  function test_apply_changeset_rdfxml_sets_content_type() {
    $fake_request_factory = new FakeRequestFactory();
    $fake_request = new FakeHttpRequest( new HttpResponse() );
    $fake_request_factory->register('POST', "http://example.org/store/services/sparql", $fake_request );

    $ss = new BigfootSparqlService("http://example.org/store/services/sparql");
    $ss->request_factory = $fake_request_factory;

    $response = $ss->describe( 'http://example.org/scooby' );
    $this->assertTrue( in_array('Content-Type: application/x-www-form-urlencoded', $fake_request->get_headers() ) );
  }

  function test_describe_multiple_uris_posts_to_service_uri() {
    $fake_request_factory = new FakeRequestFactory();
    $fake_request = new FakeHttpRequest( new HttpResponse() );
    $fake_request_factory->register('POST', "http://example.org/store/services/sparql", $fake_request );

    $ss = new BigfootSparqlService("http://example.org/store/services/sparql");
    $ss->request_factory = $fake_request_factory;

    $response = $ss->describe( array( 'http://example.org/scooby', 'http://example.org/shaggy' )  );
    $this->assertTrue( $fake_request->was_executed() );
  }

  function test_describe_multiple_uris_posts_query() {
    $fake_request_factory = new FakeRequestFactory();
    $fake_request = new FakeHttpRequest( new HttpResponse() );
    $fake_request_factory->register('POST', "http://example.org/store/services/sparql", $fake_request );

    $ss = new BigfootSparqlService("http://example.org/store/services/sparql");
    $ss->request_factory = $fake_request_factory;

    $response = $ss->describe( array( 'http://example.org/scooby', 'http://example.org/shaggy', 'http://example.org/velma' )  );
    $this->assertEquals( "query=DESCRIBE+%3Chttp%3A%2F%2Fexample.org%2Fscooby%3E+%3Chttp%3A%2F%2Fexample.org%2Fshaggy%3E+%3Chttp%3A%2F%2Fexample.org%2Fvelma%3E", $fake_request->get_body() );
  }

  function test_describe_to_triple_list() {
    $fake_response = new HttpResponse();
    $fake_response->status_code = 200;
    $fake_response->body = '<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:ex="http://example.org/">
	<rdf:Description rdf:about="http://example.org/subj">
    <ex:pred rdf:resource="http://example.org/obj" />
  </rdf:Description>
</rdf:RDF>';

    $fake_request_factory = new FakeRequestFactory();
    $fake_request = new FakeHttpRequest( $fake_response );
    $fake_request_factory->register('POST', "http://example.org/store/services/sparql", $fake_request );

    $ss = new BigfootSparqlService("http://example.org/store/services/sparql");
    $ss->request_factory = $fake_request_factory;
  
    $triples = $ss->describe_to_triple_list( 'http://example.org/subj' );
    $this->assertTrue( is_array( $triples ) );
  }


  function test_describe_to_triple_list_parses_response() {
    $fake_response = new HttpResponse();
    $fake_response->status_code = 200;
    $fake_response->body = '<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:ex="http://example.org/">
	<rdf:Description rdf:about="http://example.org/subj">
    <ex:pred rdf:resource="http://example.org/obj" />
  </rdf:Description>
</rdf:RDF>';

    $fake_request_factory = new FakeRequestFactory();
    $fake_request = new FakeHttpRequest( $fake_response );
    $fake_request_factory->register('POST', "http://example.org/store/services/sparql", $fake_request );

    $ss = new BigfootSparqlService("http://example.org/store/services/sparql");
    $ss->request_factory = $fake_request_factory;
  
    $triples = $ss->describe_to_triple_list( 'http://example.org/subj' );

    $this->assertEquals( 1, count( $triples ) );
    $this->assertEquals( 'uri', $triples[0]['s']['type'] );
    $this->assertEquals( 'http://example.org/subj', $triples[0]['s']['uri'] );
    $this->assertEquals( 'http://example.org/pred', $triples[0]['p'] );
    $this->assertEquals( 'uri', $triples[0]['o']['type'] );
    $this->assertEquals( 'http://example.org/obj', $triples[0]['o']['uri'] );

  }

  function test_graph_posts_to_service_uri() {
    $fake_request_factory = new FakeRequestFactory();
    $fake_request = new FakeHttpRequest( new HttpResponse() );
    $fake_request_factory->register('POST', "http://example.org/store/services/sparql", $fake_request );

    $ss = new BigfootSparqlService("http://example.org/store/services/sparql");
    $ss->request_factory = $fake_request_factory;

    $response = $ss->graph( 'construct {?s ?p ?o } where { ?s ?p ?o .}' );
    $this->assertTrue( $fake_request->was_executed() );
  }

  function test_graph_uri_posts_query() {
    $fake_request_factory = new FakeRequestFactory();
    $fake_request = new FakeHttpRequest( new HttpResponse() );
    $fake_request_factory->register('POST', "http://example.org/store/services/sparql", $fake_request );

    $ss = new BigfootSparqlService("http://example.org/store/services/sparql");
    $ss->request_factory = $fake_request_factory;

    $response = $ss->graph( 'construct {?s ?p ?o } where { ?s ?p ?o .}' );
    $this->assertEquals( "query=construct+%7B%3Fs+%3Fp+%3Fo+%7D+where+%7B+%3Fs+%3Fp+%3Fo+.%7D", $fake_request->get_body() );
  }

  function test_graph_to_triple_list() {
    $fake_response = new HttpResponse();
    $fake_response->status_code = 200;
    $fake_response->body = '<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:ex="http://example.org/">
	<rdf:Description rdf:about="http://example.org/subj">
    <ex:pred rdf:resource="http://example.org/obj" />
  </rdf:Description>
</rdf:RDF>';

    $fake_request_factory = new FakeRequestFactory();
    $fake_request = new FakeHttpRequest( $fake_response );
    $fake_request_factory->register('POST', "http://example.org/store/services/sparql", $fake_request );

    $ss = new BigfootSparqlService("http://example.org/store/services/sparql");
    $ss->request_factory = $fake_request_factory;
  
    $triples = $ss->graph_to_triple_list( 'construct {?s ?p ?o } where { ?s ?p ?o .}' );
    $this->assertTrue( is_array( $triples ) );
  }


  function test_graph_to_triple_list_parses_response() {
    $fake_response = new HttpResponse();
    $fake_response->status_code = 200;
    $fake_response->body = '<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:ex="http://example.org/">
	<rdf:Description rdf:about="http://example.org/subj">
    <ex:pred rdf:resource="http://example.org/obj" />
  </rdf:Description>
</rdf:RDF>';

    $fake_request_factory = new FakeRequestFactory();
    $fake_request = new FakeHttpRequest( $fake_response );
    $fake_request_factory->register('POST', "http://example.org/store/services/sparql", $fake_request );

    $ss = new BigfootSparqlService("http://example.org/store/services/sparql");
    $ss->request_factory = $fake_request_factory;
  
    $triples = $ss->graph_to_triple_list( 'construct {?s ?p ?o } where { ?s ?p ?o .}' );

    $this->assertEquals( 1, count( $triples ) );
    $this->assertEquals( 'uri', $triples[0]['s']['type'] );
    $this->assertEquals( 'http://example.org/subj', $triples[0]['s']['uri'] );
    $this->assertEquals( 'http://example.org/pred', $triples[0]['p'] );
    $this->assertEquals( 'uri', $triples[0]['o']['type'] );
    $this->assertEquals( 'http://example.org/obj', $triples[0]['o']['uri'] );

  }

  function test_select_posts_to_service_uri() {
    $fake_request_factory = new FakeRequestFactory();
    $fake_request = new FakeHttpRequest( new HttpResponse() );
    $fake_request_factory->register('POST', "http://example.org/store/services/sparql", $fake_request );

    $ss = new BigfootSparqlService("http://example.org/store/services/sparql");
    $ss->request_factory = $fake_request_factory;

    $response = $ss->select( 'http://example.org/scooby' );
    $this->assertTrue( $fake_request->was_executed() );
  }

  function test_select_posts_query() {
    $fake_request_factory = new FakeRequestFactory();
    $fake_request = new FakeHttpRequest( new HttpResponse() );
    $fake_request_factory->register('POST', "http://example.org/store/services/sparql", $fake_request );

    $ss = new BigfootSparqlService("http://example.org/store/services/sparql");
    $ss->request_factory = $fake_request_factory;

    $response = $ss->graph( 'select ?s where { ?s ?p ?o .}' );
    $this->assertEquals( "query=select+%3Fs+where+%7B+%3Fs+%3Fp+%3Fo+.%7D", $fake_request->get_body() );
  }


  function test_select_to_array() {
    $fake_response = new HttpResponse();
    $fake_response->status_code = 200;
    $fake_response->body = '<?xml version="1.0"?>
<sparql
    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
    xmlns:xs="http://www.w3.org/2001/XMLSchema#"
    xmlns="http://www.w3.org/2005/sparql-results#" >
  <head>
    <variable name="s"/>
  </head>
  <results ordered="false" distinct="true">
    <result>
      <binding name="s">
        <uri>http://api.talis.local/bf/stores/engagetenantstore/items/1173364330999#self</uri>

      </binding>
    </result>
    <result>
      <binding name="s">
        <uri>http://api.talis.local/bf/stores/engagetenantstore/items/1173371909685#self</uri>
      </binding>
    </result>
    <result>

      <binding name="s">
        <uri>http://api.talis.local/bf/stores/engagetenantstore/items/1173386584025#self</uri>
      </binding>
    </result>
  </results>
</sparql>
';

    $fake_request_factory = new FakeRequestFactory();
    $fake_request = new FakeHttpRequest( $fake_response );
    $fake_request_factory->register('POST', "http://example.org/store/services/sparql", $fake_request );

    $ss = new BigfootSparqlService("http://example.org/store/services/sparql");
    $ss->request_factory = $fake_request_factory;
  
    $array = $ss->select_to_array( 'select distinct ?s where { ?s ?p ?o .} limit 3' );
    $this->assertTrue( is_array( $array ) );

  }


  function test_select_to_array_parses_response() {
    $fake_response = new HttpResponse();
    $fake_response->status_code = 200;
    $fake_response->body = '<?xml version="1.0"?>
<sparql
    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
    xmlns:xs="http://www.w3.org/2001/XMLSchema#"
    xmlns="http://www.w3.org/2005/sparql-results#" >
  <head>
    <variable name="s"/>
    <variable name="p"/>
    <variable name="o"/>
  </head>
  <results ordered="false" distinct="true">
    <result>
      <binding name="s">

        <uri>http://api.talis.local/bf/stores/engagetenantstore/items/1173364330999#self</uri>
      </binding>
      <binding name="p">
        <uri>http://www.w3.org/1999/02/22-rdf-syntax-ns#subject</uri>
      </binding>
      <binding name="o">
        <uri>http://api.talis.local/bf/stores/engagetenantstore/items/1174262688178#self</uri>

      </binding>
    </result>
    <result>
      <binding name="s">
        <uri>http://api.talis.local/bf/stores/engagetenantstore/items/1173364330999#self</uri>

      </binding>
      <binding name="p">
        <uri>http://www.w3.org/1999/02/22-rdf-syntax-ns#object</uri>
      </binding>
      <binding name="o">
        <literal>1a3c47c9-fb29-4fd2-a061-a3b72328c96b</literal>
      </binding>
    </result>

  </results>
</sparql>';

    $fake_request_factory = new FakeRequestFactory();
    $fake_request = new FakeHttpRequest( $fake_response );
    $fake_request_factory->register('POST', "http://example.org/store/services/sparql", $fake_request );

    $ss = new BigfootSparqlService("http://example.org/store/services/sparql");
    $ss->request_factory = $fake_request_factory;
  
    $array = $ss->select_to_array( 'select distinct ?s where { ?s ?p ?o .} limit 3' );

    $this->assertEquals( 2, count( $array ) );

    $this->assertEquals( 3, count($array[0]) );
    $this->assertEquals( 'uri', $array[0]['s']['type'] );
    $this->assertEquals( 'http://api.talis.local/bf/stores/engagetenantstore/items/1173364330999#self', $array[0]['s']['value'] );
    $this->assertEquals( 'uri', $array[0]['p']['type'] );
    $this->assertEquals( 'http://www.w3.org/1999/02/22-rdf-syntax-ns#subject', $array[0]['p']['value'] );
    $this->assertEquals( 'uri', $array[0]['o']['type'] );
    $this->assertEquals( 'http://api.talis.local/bf/stores/engagetenantstore/items/1174262688178#self', $array[0]['o']['value'] );

    $this->assertEquals( 3, count($array[1]) );
    $this->assertEquals( 'uri', $array[1]['s']['type'] );
    $this->assertEquals( 'http://api.talis.local/bf/stores/engagetenantstore/items/1173364330999#self', $array[1]['s']['value'] );
    $this->assertEquals( 'uri', $array[1]['p']['type'] );
    $this->assertEquals( 'http://www.w3.org/1999/02/22-rdf-syntax-ns#object', $array[1]['p']['value'] );
    $this->assertEquals( 'literal', $array[1]['o']['type'] );
    $this->assertEquals( '1a3c47c9-fb29-4fd2-a061-a3b72328c96b', $array[1]['o']['value'] );
  }


  function test_parse_select_results_xml_lang() {
    $xml = '<?xml version="1.0"?>
<sparql
    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
    xmlns:xs="http://www.w3.org/2001/XMLSchema#"
    xmlns="http://www.w3.org/2005/sparql-results#" >
  <head>
    <variable name="s"/>
    <variable name="p"/>
    <variable name="o"/>
  </head>
  <results ordered="false" distinct="true">
    <result>
      <binding name="s">
        <uri>http://api.talis.local/bf/stores/engagetenantstore/items/1173364330999#self</uri>
      </binding>
      <binding name="p">
        <uri>http://www.w3.org/1999/02/22-rdf-syntax-ns#object</uri>
      </binding>
      <binding name="o">
        <literal xml:lang="he">1a3c47c9-fb29-4fd2-a061-a3b72328c96b</literal>
      </binding>
    </result>

  </results>
</sparql>';

    $ss = new BigfootSparqlService("http://example.org/store/services/sparql");
    $array = $ss->parse_select_results($xml );

    $this->assertEquals( 1, count( $array ) );

    $this->assertEquals( 3, count($array[0]) );
    $this->assertEquals( 'literal', $array[0]['o']['type'] );
    $this->assertEquals( '1a3c47c9-fb29-4fd2-a061-a3b72328c96b', $array[0]['o']['value'] );
    $this->assertEquals( 'he', $array[0]['o']['lang'] );
  }


  function test_parse_select_results_datatype() {
    $xml = '<?xml version="1.0"?>
<sparql
    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
    xmlns:xs="http://www.w3.org/2001/XMLSchema#"
    xmlns="http://www.w3.org/2005/sparql-results#" >
  <head>
    <variable name="s"/>
    <variable name="p"/>
    <variable name="o"/>
  </head>
  <results ordered="false" distinct="true">
    <result>
      <binding name="s">
        <uri>http://api.talis.local/bf/stores/engagetenantstore/items/1173364330999#self</uri>
      </binding>
      <binding name="p">
        <uri>http://www.w3.org/1999/02/22-rdf-syntax-ns#object</uri>
      </binding>
      <binding name="o">
        <literal datatype="http://example.com/dt">1a3c47c9-fb29-4fd2-a061-a3b72328c96b</literal>
      </binding>
    </result>

  </results>
</sparql>';

    $ss = new BigfootSparqlService("http://example.org/store/services/sparql");
    $array = $ss->parse_select_results($xml );

    $this->assertEquals( 1, count( $array ) );

    $this->assertEquals( 3, count($array[0]) );
    $this->assertEquals( 'literal', $array[0]['o']['type'] );
    $this->assertEquals( '1a3c47c9-fb29-4fd2-a061-a3b72328c96b', $array[0]['o']['value'] );
    $this->assertEquals( 'http://example.com/dt', $array[0]['o']['datatype'] );
  }

}
